﻿using Bettzueche.RLLibrary.Types;
using System;

namespace Bettzueche.RLLibrary.RLTypes
{
    /// <summary>
    /// A general State (or Observation) Type consting of various int, double, char values.
    /// </summary>
    /// <remarks>
    /// A RL-State represents the agent's state in the Environment, the Environment's state respectively. E.g. in a board game,
    /// this could be the Array IntValues, where the indexes represent the fields an the values encodes the meeple types.
    /// In that case DoubleValues and CharValues are empty Arrays.<para>
    /// In some cases you need mixed types for your State model. Of course, this is supported by this type.</para>
    /// </remarks>
    public class GeneralState : IGeneralType, IState {

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="GeneralState"/> with empty values.
        /// </summary>
        public GeneralState()
            : this(new int[0], new double[0], new char[0]) {

        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GeneralState"/>.
        /// </summary>
        /// <param name="discretes">The discretes.</param>
        /// <param name="continiouses">The continiouses.</param>
        /// <param name="chars">The chars.</param>
        /// <exception cref="ArgumentNullException">if one parameter is null.</exception>
        public GeneralState(int[] discretes, double[] continiouses, char[] chars) {
            if (discretes == null)
                throw new ArgumentNullException("discretes");
            _intValues = discretes;
            if (continiouses == null)
                throw new ArgumentNullException("continiouses");
            _doubleValues = continiouses;
            if (chars == null)
                throw new ArgumentNullException("chars");
            _charValues = chars;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GeneralState"/>.
        /// </summary>
        /// <param name="discrete">The discrete value(s).</param>
        public GeneralState(params int[] discrete) 
            : this(discrete,new double[0], new char[0]) {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GeneralState"/>.
        /// </summary>
        /// <param name="continious">The continious value(s).</param>
        public GeneralState(params double[] continious)
            : this(new int[0], continious, new char[0]) {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GeneralState"/>.
        /// </summary>
        /// <param name="characters">The character value(s).</param>
        public GeneralState(params char[] characters)
            : this(new int[0], new double[0], characters) {
        }

        #endregion

        #region IGeneralType Members

        /// <summary>
        /// Gets the total count of values.
        /// </summary>
        public int Count {
            get { return IntValues.Length + DoubleValues.Length + CharValues.Length; }
        }

        /// <summary>
        /// Gets the count of discrete values.
        /// </summary>
        public int IntCount {
            get { return IntValues.Length; }
        }

        /// <summary>
        /// Gets the count of continius values.
        /// </summary>
        public int DoubleCount {
            get { return DoubleValues.Length; }
        }

        /// <summary>
        /// Gets the char count.
        /// </summary>
        public int CharCount {
            get { return CharValues.Length; }
        }


        int[] _intValues;
        /// <summary>
        /// Gets or sets the discrete values (Array reference).
        /// </summary>
        /// <value>
        /// The int values, not null.
        /// </value>
        public int[] IntValues {
            get {
                return _intValues;
            }
            set {
                if (value == null)
                    throw new ArgumentNullException("IntValues");
                _intValues = value;
            }
        }

        double[] _doubleValues;
        /// <summary>
        /// Gets or sets the continious values (Array reference).
        /// </summary>
        /// <value>
        /// The double values.
        /// </value>
        public double[] DoubleValues {
            get {
                return _doubleValues;
            }
            set {
                if (value == null)
                    throw new ArgumentNullException("DoubleValues");
                _doubleValues = value;
            }
        }

        char[] _charValues;
        /// <summary>
        /// Gets or sets the char values (Array reference).
        /// </summary>
        /// <value>
        /// The char values, not null.
        /// </value>
        public char[] CharValues {
            get {
                return _charValues;
            }
            set {
                if (value == null)
                    throw new ArgumentNullException("CharValues");
                _charValues = value;
            }
        }

        #endregion
    }
}
